package com.study.remoteServerIo.utils;

import com.jcraft.jsch.*;
import com.study.remoteServerIo.config.SftpConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

/**
 * @author wei.zhao
 * @description:
 * @date 2022年07月13日 14:20
 */
@Slf4j
@Component
public class SftpUtil {

    @Autowired
    SftpConfig sftpConfig;

    private Session session;

    private ChannelSftp channel;

    /**
     * 连接sftp服务器
     *
     * @throws JSchException JSchException
     */
    @PostConstruct
    public void connectServer() throws JSchException {
        JSch jsch = new JSch();
        // 根据用户名，主机ip，端口获取一个Session对象
        session = jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHost(), sftpConfig.getPort());
        // 设置密码
        session.setPassword(sftpConfig.getPassword());
        // 为Session对象设置properties
        Properties config = new Properties();
        // 设置第一次登陆的时候提示，可选值：(ask | yes | no)
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        // 通过Session建立链接
        session.connect();
        // 打开SFTP通道
        channel = (ChannelSftp) session.openChannel("sftp");
        // 建立SFTP通道的连接
        channel.connect();
    }

    private List<String> getDirList(String path, String appendPath) throws SftpException {
        if (!appendPath.endsWith("/")) {
            appendPath += "/";
        }
        List<String> result = new ArrayList<>();
        List<String> dirList = this.getDirList(path + appendPath);
        for (String fileName : dirList) {
            result.add(appendPath + fileName);
        }
        return result;
    }

    public List<String> getDirList(String path) throws SftpException {
        List<String> result = new ArrayList<>();
        if (!path.endsWith("/")) {
            path += "/";
        }
        Vector vector = channel.ls(path);
        for (Object object : vector) {
            ChannelSftp.LsEntry temp = (ChannelSftp.LsEntry) object;
            if (temp.getFilename().startsWith(".")) {
                continue;
            }
            if (temp.getAttrs().isDir()) {
                List<String> dirList = this.getDirList(path, temp.getFilename());
                result.addAll(dirList);
            } else {
                result.add(temp.getFilename());
            }
        }
        return result;
    }

    public List<String> getFileList(String path) throws SftpException {
        List<String> result = new ArrayList<>();
        if (!path.endsWith("/")) {
            path += "/";
        }
        Vector vector = channel.ls(path);
        for (Object object : vector) {
            ChannelSftp.LsEntry temp = (ChannelSftp.LsEntry) object;
            System.out.println(temp.getFilename());
            if (temp.getFilename().startsWith(".")) {
                continue;
            }
            if (temp.getAttrs().isDir()) {
                List<String> dirList = this.getFileList(path + temp.getFilename());
                result.addAll(dirList);
            } else {
                result.add(temp.getFilename());
            }
        }
        return result;
    }

    public long getFileSize(String file) throws SftpException, IOException {
        Vector ls = channel.ls(file);
        if (ls == null) {
            throw new IOException("file " + file + " not found!");
        }
        ChannelSftp.LsEntry temp = (ChannelSftp.LsEntry) ls.get(0);
        return temp.getAttrs().getSize();
    }

    /**
     * 下载文件
     *
     * @param remotePathFile 远程文件
     * @param localPathFile  本地文件[绝对路径]
     * @throws SftpException SftpException
     * @throws IOException   IOException
     */
    public void downloadFile(String remotePathFile, String localPathFile) throws SftpException, IOException {
        try (FileOutputStream os = new FileOutputStream(new File(localPathFile))) {
            channel.get(remotePathFile, os);
        }
    }

    /**
     * 下载文件
     *
     * @param remotePathFile 远程文件
     * @throws SftpException SftpException
     */
    public String downloadFile(String remotePathFile) throws SftpException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        channel.get(remotePathFile, outputStream);
        return new String(outputStream.toByteArray());
    }

    /**
     * 下载文件
     *
     * @param remotePathFile 远程文件
     * @param outputStream   输出流
     * @throws SftpException
     */
    public void downloadFile(String remotePathFile, OutputStream outputStream) throws SftpException {
        channel.get(remotePathFile, outputStream);
    }

    /**
     * 上传文件
     *
     * @param remoteFile 远程文件
     * @param localFile  本地文件[绝对路径]
     * @throws SftpException
     * @throws IOException
     */
    public void uploadFile(String remoteFile, File localFile) throws SftpException, IOException {
        try (FileInputStream in = new FileInputStream(localFile)) {
            channel.put(in, remoteFile);
        }
    }

    /**
     * 上传文件
     *
     * @param remoteFile 远程文件
     * @throws SftpException
     */
    public void uploadFile(String path, String remoteFile, String content) throws SftpException {
        channel.cd(path);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes());
        channel.put(inputStream, remoteFile);
    }

    /**
     * 上传文件
     *
     * @param remoteFile  远程文件
     * @param inputStream 输入流
     * @throws SftpException
     */
    public void uploadFile(String remoteFile, InputStream inputStream) throws SftpException {
        channel.put(inputStream, remoteFile);
    }

    public void mkdir(String path) throws SftpException {
        log.info("Create Directory " + path);
        String[] split = path.split("/");
        StringBuilder stringBuilder = new StringBuilder();
        for (String name : split) {
            if (!"".equals(name)) {
                stringBuilder.append("/").append(name);
                if (!this.exists(stringBuilder.toString())) {
                    log.info("Create Directory " + stringBuilder.toString());
                    channel.mkdir(stringBuilder.toString());
                }
            }
        }
    }

    public boolean exists(String path) {
        try {
            channel.ls(path);
            return true;
        } catch (SftpException e) {
            return false;
        }
    }

    @PreDestroy
    public void close() {
        if (channel != null) {
            channel.disconnect();
        }
        if (session != null) {
            session.disconnect();
        }
    }

}
